#pragma once

#include <new>

#include "../type_traits/"

namespace hamster
{
    template <typename T1, typename T2>
    inline void construct(T1 *p, const T2 &value)
    {
        new (p) T1(value);
    }

    // destroy -> first version get a pointer
    template <typename T>
    inline void destroy(T *ptr)
    {
        ptr->~T();
    }

    inline void destroy(char *, char *)
    {
        // do nothing
    }

    inline void destroy(wchar_t *, wchar_t *)
    {
        // do nothing
    }

    template <typename ForwardIterator>
    inline void __destroy_aux(ForwardIterator first, ForwardIterator last, __true_type)
    {
        // do nothing
        // POD Type Data -> Do Nothing
    }

    template <typename ForwardIterator>
    inline void __destroy_aux(ForwardIterator first, ForwardIterator last, __false_type)
    {
        for (; first != last; ++first)
        {
            destroy(&*first);
        }
    }

    // API to see whether T has a trivial destructor
    template <typename ForwardIterator, typename T>
    inline void __destroy(ForwardIterator first, ForwardIterator last, T *)
    {
        using whether_trivial_destructor = typename hamster_type_traits<T>::has_trivial_destructor;
        __destroy_aux(first, last, whether_trivial_destructor());
    }

    // destroy -> second version get two iterator -> a uniform api
    template <typename ForwardIterator>
    inline void destroy(ForwardIterator first, ForwardIterator last)
    {
        __destroy(first, last, value_type(first));
    }

}